/* This file is part of FireEscape.
 *
 * FireEscape is the intellectual work of Phillip Cheng & Allen Park.
 * All future releases or modifications of this program must include this
 * attribuation as according to the Creative Commons BY-SA license.
 *
 * FireEscape is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * FireEscape is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FireEscape.  If not, see <http://www.gnu.org/licenses/>.
 *
 * All modifications to this program should include this original statement.
 *
 * If you modify, distribute, or use the program , please contact
 * fireescape@kloudvine.com
 * http://code.google.com/p/fireescape/
 *
 * If you are interested in using FireEscape for your structure, please contact us
 * for support.
 *
 * If you do use FireEscape, please consider donating to the project.
 */
package fireescape;

import java.awt.*;
import java.util.ArrayList;
import java.awt.geom.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Represents a staircase
 * @author parkA
 */
public class Staircase extends Exit {

    //private ArrayList<Room> linkedRooms;
    public static final double betweenFloorsHeight = 45;
    public static final double staircaseHeight = 8.5;
    private static double xBuffer;
    private static double yBuffer;
    private double farthestDistanceFromEndpoint;
    private int bottomRoom;
    private int bottomFloorNum;
    private int topFloorNum;
    private int staircaseID;
    private Room staircase;

    /**
     * Constructs a staircase
     */
    public Staircase() {
        this(0, 0, 0, 0, -1, -1, -1, -1, -1);
    }

    /**
     * Constructs a staircase
     * @param x1 The x coordinate of the first corner
     * @param y1 The y coordinate of the first corner
     * @param x2 The x coordinate of the second corner
     * @param y2 The y coordinate of the second corner
     * @param r The starting room
     * @param exitNum The exit ID
     */
    public Staircase(double x1, double y1, double x2, double y2, int r, int b, int t, int exitNum, int stairID) {
        super(x1, y1, x2, y2, -1, exitNum);
        //linkedRooms = new ArrayList<Room>();
        bottomRoom = r;
        bottomFloorNum = b;
        topFloorNum = t;
        staircaseID = stairID;
        xBuffer = 2 * BotAI.botRadius;
        yBuffer = BotAI.botRadius + BotAI.defaultDistance / 2;
        farthestDistanceFromEndpoint = FireEscapeGUI.distance(0, 0, getLength(), BotAI.defaultDistance / 2);
        overrideRect();
        constructStaircase();
    }

    public int getStaircaseID() {
        return staircaseID;
    }

    public void constructStaircase() {
        ArrayList<Point2D.Double> vertices = new ArrayList<Point2D.Double>();
        vertices.add(new Point2D.Double(0, 0));
        vertices.add(new Point2D.Double((topFloorNum - bottomFloorNum) * betweenFloorsHeight + 2 * xBuffer, 0));
        vertices.add(new Point2D.Double((topFloorNum - bottomFloorNum) * betweenFloorsHeight + 2 * xBuffer, staircaseHeight + 2 * yBuffer));
        vertices.add(new Point2D.Double(0, staircaseHeight + 2 * yBuffer));
        staircase = new Room(vertices, -1, -1, false);
    }

    public boolean canMoveOntoStairs(Bot b) {
        int floorNum = Map.getRoom(b.getRoomID()).getFloorNum();
        double distanceFromEndpoint = FireEscapeGUI.distance(this.getX1(), this.getY1(), b.getX(), b.getY());
        double newX = (floorNum - bottomFloorNum) * betweenFloorsHeight + xBuffer;
        double newY = distanceFromEndpoint / this.getFarthestDistanceFromEndpoint() * staircaseHeight + yBuffer;
        return staircase.totalNoOverlapCheck(newX, newY);
    }

    public void addBot(Bot b) {
        int floorNum = Map.getRoom(b.getRoomID()).getFloorNum();
        double distanceFromEndpoint = FireEscapeGUI.distance(this.getX1(), this.getY1(), b.getX(), b.getY());
        double newX = (floorNum - bottomFloorNum) * betweenFloorsHeight + xBuffer;
        double newY = distanceFromEndpoint / this.getFarthestDistanceFromEndpoint() * staircaseHeight + yBuffer;
        if (newY > staircaseHeight + 2 * yBuffer - BotAI.botRadius) {
            Logger.getLogger("FireEscapeLog").log(Level.FINE, "Staircase teleportation is not working");
            System.out.println("Staircase teleportation is not working");
        }
        b.setCoords(newX, newY);
        staircase.addBot(b);
    }

    public void removeBot(Bot b) {
        staircase.removeBot(b);
    }

    public Bot getBot(int index) {
        return staircase.getBot(index);
    }

    public int getNumBots() {
        return staircase.getNumBots();
    }

    public boolean onStaircaseLegit(Bot b) {
        return staircase.botInRoom(b.getX(), b.getY(), null);
    }

    public double minDistanceToWall(Bot b) {
        return staircase.minDistanceToWall(b);
    }

    public double getFarthestDistanceFromEndpoint() {
        return farthestDistanceFromEndpoint;
    }

    public void overrideRect() {
        ArrayList<Point2D.Double> vertices = new ArrayList<Point2D.Double>();
        Line2D.Double line = super.getLine();
        double halfWidth = BotAI.botRadius + BotAI.defaultDistance / 2;
        double halfLength = BotAI.botRadius;
        double angle = BotAI.calculateAngle(line.getX1(), line.getY1(), line.getX2(), line.getY2());
        vertices.add(new Point2D.Double(line.getX1() - Math.sin(angle) * halfWidth - Math.cos(angle) * halfLength,
                line.getY1() + Math.cos(angle) * halfWidth - Math.sin(angle) * halfLength));
        vertices.add(new Point2D.Double(line.getX1() + Math.sin(angle) * halfWidth - Math.cos(angle) * halfLength,
                line.getY1() - Math.cos(angle) * halfWidth - Math.sin(angle) * halfLength));
        vertices.add(new Point2D.Double(line.getX2() + Math.sin(angle) * halfWidth + Math.cos(angle) * halfLength,
                line.getY2() - Math.cos(angle) * halfWidth + Math.sin(angle) * halfLength));
        vertices.add(new Point2D.Double(line.getX2() - Math.sin(angle) * halfWidth + Math.cos(angle) * halfLength,
                line.getY2() + Math.cos(angle) * halfWidth + Math.sin(angle) * halfLength));
        RoomShape rect = new RoomShape(vertices);
        super.overrideRect(rect);
        if (Map.drawExitRects) {
            RoomShape drawnRect = new RoomShape(FireEscapeGUI.scale(vertices));
            super.overrideDrawnRect(drawnRect);
        }
    }

    /**
     * Sets a new room
     * Is overrided to do nothing - is not neccessary for a staircase
     * @param r The new room
     * @return Always return true to do nothing
     */
    @Override
    public boolean setRoom(int r) {
        //linkedRooms.add(r);
        return true;
    }

    /**
     * Returns the bottom room of the staircase
     * @param r The room index - is only here because this method needs to be overrided
     * @return The bottom room
     */
    @Override
    public int connectedToID(int r) {
        return bottomRoom;
    }

    /**
     * Draws the staircase
     * @param g The Graphics2D object used for drawing
     */
    @Override
    public void paint(Graphics2D g) {
        g.setColor(Color.darkGray);
        g.draw(getDrawnLine());
        if (Map.drawExitRects) {
            g.setColor(Color.green);
            getDrawnRect().draw(g);
        }
    }

    public void drawStaircase(Graphics2D g) {
        staircase.paint(g);
        g.setColor(Color.white);
        for (int i = bottomFloorNum; i <= topFloorNum; i++) {
            double x = betweenFloorsHeight * (i - bottomFloorNum) + xBuffer;
            g.draw(new Line2D.Double(FireEscapeGUI.scale * x, FireEscapeGUI.scale * yBuffer, FireEscapeGUI.scale * x, FireEscapeGUI.scale * (staircaseHeight + yBuffer)));
        }
    }

    /**
     * Returns a description of the staircase
     * @return The coordinates of the staircase and the word "Staircase"
     */
    @Override
    public String toString() {
        return super.toString() + " Staircase";
    }
}
